/* -LICENSE-START-
** Copyright (c) 2009 Blackmagic Design
**
** Permission is hereby granted, free of charge, to any person or organization
** obtaining a copy of the software and accompanying documentation covered by
** this license (the "Software") to use, reproduce, display, distribute,
** execute, and transmit the Software, and to prepare derivative works of the
** Software, and to permit third-parties to whom the Software is furnished to
** do so, all subject to the following:
** 
** The copyright notices in the Software and this entire statement, including
** the above license grant, this restriction and the following disclaimer,
** must be included in all copies of the Software, in whole or in part, and
** all derivative works of the Software, unless such copies or derivative
** works are solely in the form of machine-executable object code generated by
** a source language processor.
** 
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
** SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
** FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
** ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
** -LICENSE-END-
*/
//
//  SyncController.h
//  Signal Generator
//

#ifndef __SignalGenerator_H__
#define __SignalGenerator_H__

#include "DeckLinkAPI.h"

#include <QMessageBox>
#include <QWidget>
#include <QGLWidget>
#include <QMutex>

#include "ui_SignalGenerator.h"

class Timecode
{
public:
		Timecode(int f) 
			: fps(f),hours_(0),minutes_(0),seconds_(0),frames_(0)
			{ return; }
		void update() 
		{ 
			if (frames_ >= fps - 1)
			{
				frames_ = 0;
				seconds_++;
			}
			else
				frames_++;
			
			if (seconds_ >= 60)
			{
				seconds_ = 0;
				minutes_++;
			}
			
			if (minutes_ >= 60)
			{
				minutes_ = 0;
				hours_++;
			}
			if (hours_ >= 24)
			{
				frames_ = 0;
				seconds_ = 0;
				minutes_ = 0;
				hours_ = 0;
			}
		}
		int hours() { return hours_; }
		int minutes() { return minutes_; }
		int seconds() { return seconds_; }
		int frames() { return frames_; }
private:
	int fps;
	unsigned long frames_;
	int seconds_;
	int minutes_;
	int hours_;
};

enum OutputSignal {
	kOutputSignalPip		= 0,
	kOutputSignalDrop		= 1
};


class CDeckLinkGLWidget;
class PlaybackDelegate;

class SignalGenerator : public QDialog {
Q_OBJECT
public:
	SignalGenerator();
	Ui::SignalGeneratorDialog *ui;
	CDeckLinkGLWidget *previewView;
	
	PlaybackDelegate*			playerDelegate;
	
	bool						running;
	IDeckLink*					deckLink;
	IDeckLinkOutput*			deckLinkOutput;
	
	uint32_t					frameWidth;
	uint32_t					frameHeight;
	BMDTimeValue				frameDuration;
	BMDTimeScale				frameTimescale;
	uint32_t					framesPerSecond;
	IDeckLinkMutableVideoFrame*	videoFrameBlack;
	IDeckLinkMutableVideoFrame*	videoFrameBars;
	uint32_t					totalFramesScheduled;
	//
	OutputSignal				outputSignal;
	void*						audioBuffer;
	uint32_t					audioBufferSampleLength;
	uint32_t					audioSamplesPerFrame;
	uint32_t					audioChannelCount;
	BMDAudioSampleRate			audioSampleRate;
	uint32_t					audioSampleDepth;
	uint32_t					totalAudioSecondsScheduled;
	
	BMDTimecodeFormat			timeCodeFormat;

	void closeEvent(QCloseEvent *event);

	void setup();

 	void scheduleNextFrame(bool prerolling);
	void writeNextAudioSamples();
	void enableInterface(bool);

	void startRunning();
	void stopRunning();
public slots:
	
	void toggleStart();
private:
	QGridLayout *layout;
	Timecode *timeCode;
};

class PlaybackDelegate : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback
{
	SignalGenerator*				mController;
	IDeckLinkOutput*			mDeckLinkOutput;
	
public:
						PlaybackDelegate (SignalGenerator* owner, IDeckLinkOutput* deckLinkOutput);
	
	// IUnknown needs only a dummy implementation
	virtual HRESULT		QueryInterface (REFIID iid, LPVOID *ppv)	{return E_NOINTERFACE;}
	virtual ULONG		AddRef ()									{return 1;}
	virtual ULONG		Release ()									{return 1;}
	
	virtual HRESULT		ScheduledFrameCompleted (IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result);
	virtual HRESULT		ScheduledPlaybackHasStopped ();
	virtual HRESULT		RenderAudioSamples (bool preroll);
};

void	FillSine (void* audioBuffer, uint32_t samplesToWrite, uint32_t channels, uint32_t sampleDepth);
void	FillColourBars (IDeckLinkVideoFrame* theFrame);
void	FillBlack (IDeckLinkVideoFrame* theFrame);
void	ScheduleNextVideoFrame (void);

#endif
